package cn.wit.summit.chwan.tools.downloadtool;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.atomic.AtomicBoolean;

import cn.wit.summit.chwan.models.event.DownloadEvent;
import cn.wit.summit.chwan.utils.LogUtils;
import cn.wit.summit.chwan.utils.StringUtils;
import cn.wit.summit.chwan.utils.UtilsMy;

/**
 * Created by Alan on 2018/4/4.
 */

public class DownloadTask implements Runnable {

    private String TAG = "DownloadTask>>:";

    private long range = 0;       //已存在文件已下载长度
    private long actualSize = 0;  //http返回的文件总长度
    private long expectSize;      //文件总大小
    private int tryCount = 3;     //重试下载次数
    private long curSize;     //存储写入文件起点
    private String speed;     //下载速度
    private int percent;   //完成下载比例
    private String gameId;   //完成下载比例

    private int disSeedTime = 200;

    private AtomicBoolean stopFlag = new AtomicBoolean(false);
    private AtomicBoolean deletFlag = new AtomicBoolean(false);
    private HttpURLConnection connectionx;
    private HttpURLConnection connection;
    private RandomAccessFile out = null;
    private InputStream in = null;

    private String downloadUrl;    //下载url
    private String downloadPath;   //下载后文件所在的目录
    private Handler handler;

    public DownloadTask(String downloadUrl, String downloadPath, String gameId, long totalSize) {
        this.downloadUrl = downloadUrl;
        this.downloadPath = downloadPath;
        this.gameId = gameId;
        this.expectSize = totalSize;
    }

    public void cancel() {
        LogUtils.e(TAG + "cancle");
        disSeedTime = 200;
        this.stopFlag.set(true);
    }

    public void delet() {
        disSeedTime = 200;
        this.deletFlag.set(true);
    }

    @Override
    public void run() {
        sendMsg(DownLoadStatusConfig.START);
        boolean isDownFinish = false;
        //开始下载
        while (tryCount >= 0) {
            File file2;
            if (StringUtils.isEmpty(downloadUrl)) {
                LogUtils.e(TAG + "下载地址为空");
                sendMsg(DownLoadStatusConfig.DOWNLOAD_ERROR);
                return;
            }

            File file = new File(downloadPath).getParentFile();
            if (!file.exists()) {
                LogUtils.e(TAG + "存放路径不存在");
                sendMsg(DownLoadStatusConfig.DOWNLOAD_ERROR);
                return;
            }

            file2 = new File(downloadPath);
            if (file2.exists()) {//文件已存在
                range = file2.length();
                LogUtils.e(TAG + "文件已存在");
            } else {//文件不存在
                try {
                    LogUtils.e(TAG + "createnewFile");

                    file2.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                    sendMsg(DownLoadStatusConfig.DOWNLOAD_ERROR);
                    return;
                }
            }

            if (stopFlag.get()) {
                stop();
                return;
            }
            if (deletFlag.get()) {
                closedAndDelet();
                return;
            }

            LogUtils.e(TAG + "while");
            if (stopFlag.get()) {
                stop();
                return;
            }
            if (deletFlag.get()) {
                closedAndDelet();
                return;
            }
            try {
                URL netUrl = new URL(downloadUrl);
                //只读取头信息获取文件总大小，用来识别是否是真正的要下载的目标文件
                connectionx = (HttpURLConnection) netUrl.openConnection();
                connectionx.setConnectTimeout(3000);
                connectionx.setReadTimeout(3000);
                connectionx.setRequestProperty("Connection", "Keep-Alive");
                connectionx.setRequestMethod("GET");
                connectionx.setRequestProperty("Accept-Encoding", "identity");
                connectionx.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36");

                long lenceAll = connectionx.getContentLength();

                if(lenceAll == -1){
                    try {
                        lenceAll = Long.parseLong(connectionx.getHeaderField("Content-Length"));
                    }catch (Exception e){
                        if (tryCount <= 0) {
                            sendMsg(DownLoadStatusConfig.DOWNLOAD_ERROR);
                            return;
                        }
                        tryCount--;
                        continue;
                    }
                }

                if(lenceAll==-1){
                    if (tryCount <= 0) {
                        sendMsg(DownLoadStatusConfig.DOWNLOAD_ERROR);
                        return;
                    }
                    tryCount--;
                    continue;
                }

                if (lenceAll == range) {
                    isDownFinish = true;
                    LogUtils.e(TAG + "hasdownfinish");
                    return;
                }
                connection = (HttpURLConnection) netUrl.openConnection();
                connection.setConnectTimeout(3000);
                connection.setReadTimeout(3000);
                connection.setRequestProperty("Connection", "Keep-Alive");
                connection.setRequestMethod("GET");
                connection.setRequestProperty("Accept-Encoding", "identity");
                connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36");

                if (range > 0) {//断点续传
                    connection.setRequestProperty("Range", "bytes=" + range + "-");
                    LogUtils.e(TAG + "setrange");
                }
                int status = connection.getResponseCode();
                boolean success;
                switch (status) {
                    case HttpURLConnection.HTTP_OK:
                    case HttpURLConnection.HTTP_PARTIAL:
                        String transfer_encoding = connection.getHeaderField("Transfer-Encoding");
                        if (!TextUtils.isEmpty(transfer_encoding)
                                && transfer_encoding.equalsIgnoreCase("chunked")) {
                        }
                        if (status == HttpURLConnection.HTTP_OK && range > 0) {//网络不支持断点续传，则要删除文件重新下载
                            if (file.exists()) UtilsMy.delete(file);
                        }
                        success = true;
                        break;
                    case HttpURLConnection.HTTP_MOVED_TEMP:
                    case HttpURLConnection.HTTP_MOVED_PERM:
                    case HttpURLConnection.HTTP_SEE_OTHER:
                        success = false;
                        break;
                    default:
                        success = false;
                        break;
                }
                LogUtils.e(TAG + "status " + success);
                if (!success) {
                    new Thread() {//关闭流
                        @Override
                        public void run() {
                            super.run();
                            if (connection != null) {
                                connection.disconnect();
                                connection = null;
                            }
                        }
                    }.start();

                    if (tryCount <= 0) {
                        sendMsg(DownLoadStatusConfig.DOWNLOAD_ERROR);
                    }
                    tryCount--;
                    continue;
                }

                String contentTypeConnection = connection.getHeaderField("Content-Type");
                if (StringUtils.isEmpty(contentTypeConnection)) contentTypeConnection = "";
                contentTypeConnection = contentTypeConnection.toLowerCase();
                if (contentTypeConnection.equals("application/octet-stream")
                        || contentTypeConnection.equals("application/vnd.android.package-archive")
                        || contentTypeConnection.equals("application/zip")
                        || expectSize == lenceAll) {
                    try {
                        actualSize = Long.parseLong(connection.getHeaderField("Content-Length"));
                        if (expectSize==0 && (actualSize+range)>0) {
                            expectSize = actualSize+range;
                        }
                    }catch (Exception e){
                        connection.disconnect();
                        tryCount--;
                        continue;
                    }

                } else {
                    tryCount--;
                    connection.disconnect();
                    continue;
                }

                out = new RandomAccessFile(file2, "rw");
                out.seek(range);
                curSize = range;
                in = new BufferedInputStream(connection.getInputStream());
                LogUtils.e(TAG + "startReadData");
                readData(curSize);
                break;
            } catch (Exception e) {
                e.printStackTrace();
                if (tryCount <= 0) {
                    sendMsg(DownLoadStatusConfig.DOWNLOAD_ERROR);
                }
                tryCount--;
            } finally {
                if (actualSize == 0 && !isDownFinish) {
                    sendMsg(DownLoadStatusConfig.DOWNLOAD_ERROR);
                    return;
                }

                long l = file2.length();
                if (l == actualSize + range || isDownFinish) {//下载完成
                    sendMsg(DownLoadStatusConfig.DOWNLOAD_FINISH);
                    DownloadFactory.get().deletTask(gameId);
                    close();
                    break;
                }
            }
        }
    }

    private void readData(long curSize) throws IOException {
        int bs = 4096;
        byte[] buffer = new byte[bs];
        int nRead = 0;
        long startTime = System.currentTimeMillis();
        long tempSize = curSize;
        LogUtils.e(TAG + "start while");
        while ((nRead = in.read(buffer, 0, bs)) > 0) {

            if (stopFlag.get()) {
                //中止下载
                stop();
                break;
            }
            if (deletFlag.get()) {
                closedAndDelet();
                return;
            }
            out.write(buffer, 0, nRead);
            this.curSize += nRead;
            long now = System.currentTimeMillis();
            long gap = now - startTime;
            if (gap > disSeedTime) {

                speed = UtilsMy.FormatFileSizeForSpeed(1000 * (this.curSize - tempSize) / gap);
                long a = 0;
                if (actualSize == -1) {
                    a = (this.curSize * 100) / (actualSize + range);
                } else {
                    a = (this.curSize * 100) / expectSize;
                }
                percent = (int) a;
                startTime = now;
                tempSize = this.curSize;
                sendMsg(DownLoadStatusConfig.DOWNLOADING);
                LogUtils.e(TAG + a + " ..... " + tempSize);
            }

        }
    }

    private void stop() {
        LogUtils.e(TAG + "stop");
        close();
        sendMsg(DownLoadStatusConfig.DOWNLOAD_STOP);
    }

    private void closedAndDelet() {
        LogUtils.e(TAG + "delet");
        close();
        sendMsg(DownLoadStatusConfig.DELETED);
    }

    private void close() {
        try {
            if (in != null) {
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (out != null) {
            try {
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        if (connection != null) {
            try {
                connection.disconnect();
                connection = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (connectionx != null) {
            try {
                connectionx.disconnect();
                connectionx = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void sendMsg(int status) {
        if (disSeedTime == 200 && status == DownLoadStatusConfig.DOWNLOADING)
            disSeedTime = 1500;
        else
            disSeedTime = 200;

        DownloadEvent downloadEvent = new DownloadEvent(downloadUrl, status, percent, speed, gameId);

        Bundle b = new Bundle();
        b.putSerializable("data", downloadEvent);

        Message msg = Message.obtain();
        msg.what = 1000;
        msg.setData(b);
        handler.sendMessage(msg);
    }

    public String getDownloadUrl() {
        return downloadUrl;
    }

    public String getDownloadPath() {
        return downloadPath;
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }

    public String getGameId() {
        return gameId;
    }

    public void setGameId(String gameId) {
        this.gameId = gameId;
    }
}
